package com.powernode.ssm.springAnalysis.a02;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.Controller;

/**
 * ApplicationContext子类相关
 * ClassPathXmlApplicationContext、FileSystemXmlApplicationContext
 * AnnotationConfigApplicationContext、
 * AnnotationConfigServletWebServerApplicationContext
 */
public class TestApplicationContext1 {
    public static void main(String[] args) {
//        testClassPathXmlApplicationContext();
//        testFileSystemXmlApplicationContext();

//        detailXmlProcess();

//        testAnnotationConfigApplicationContext();
        testAnnotationConfigServletWebServerApplicationContext();

         /*
            学到了什么
                a. 常见的 ApplicationContext 容器实现
                b. 内嵌容器、DispatcherServlet 的创建方法、作用
         */

    }

    //基于 java 配置类来创建, 用于 web 环境
    private static void testAnnotationConfigServletWebServerApplicationContext() {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig1.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }


    }


    @Configuration
    static class WebConfig1 {
        //创建tomcat容器，相当于springboot的内嵌tomcat服务器
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }
        //创建DispatcherServlet请求分发bean，负责处理请求分发
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }

        //注册DispatcherServlet到tomcat服务器，把两者关联
        @Bean
        public DispatcherServletRegistrationBean registrationBean1(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }
        //创建一个controller，用来接收请求
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }



    /**
     * 基于 java 配置类来创建
     * 同时创建bean的若干后处理器
     */
    private static void testAnnotationConfigApplicationContext() {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(Config.class);
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean8.class).getBean7());

    }

    /**
     * 相对于FileSystemXmlApplicationContext 和 ClassPathXmlApplicationContext
     * 该方法更加详细说明
     */
    private static void detailXmlProcess() {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        System.out.println("读取之前...");
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println("读取之后...");
        //new一个xml bean信息的读取对象
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        //读取xml文件信息
        //reader.loadBeanDefinitions(new ClassPathResource("springAnalysis/b01.xml"));
        reader.loadBeanDefinitions(new FileSystemResource("src\\main\\resources\\springAnalysis\\b01.xml"));
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

    // ⬇基于磁盘路径下 xml 格式的配置文件来创建
    private static void testFileSystemXmlApplicationContext() {
        //绝对路径
//        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
//                "D:\\linyucong\\javaCode\\SpringBoot3-PN\\ssm\\src\\main\\resources\\springAnalysis\\b01.xml");
        /**
         * 相对路径
         * 需要点击Edit Configuration，找到working directory指定工作目录到src上一级ssm
         */
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
                "src\\main\\resources\\springAnalysis\\b01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean8.class).getBean7());

    }

    // 基于 classpath 下 xml 格式的配置文件来创建
    private static void testClassPathXmlApplicationContext() {
        ApplicationContext context = new ClassPathXmlApplicationContext("springAnalysis/b01.xml");
        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }
        System.out.println(context.getBean(Bean8.class).getBean7());
    }

    @Configuration
    static class Config {
        @Bean
        public Bean7 bean7() {
            return new Bean7();
        }

        @Bean
        public Bean8 bean8(Bean7 bean7) {
            Bean8 bean8 = new Bean8();
            bean8.setBean7(bean7);
            return bean8;
        }
    }


    static class Bean7 {
    }

    static class Bean8 {

        private Bean7 bean7;

        public void setBean7(Bean7 bean7) {
            this.bean7 = bean7;
        }

        public Bean7 getBean7() {
            return bean7;
        }
    }

}
